home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
pctjdc85.arc
/
COMM.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1985-10-21
|
7KB
|
219 lines
Program Comm;
Type INS8250 = Record {Define serial port registers}
THR:Integer; {Transmit holding register}
RBR:Integer; {Receive holding register}
IER:Integer; {Interrupt enable register}
LCR:Integer; {Line control register}
MCR:Integer; {Modem control register}
LSR:Integer; {Line status register}
MSR:Integer; {Modem status register}
End;
Registers = Record {Define the 8086 chip registers}
AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags:Integer;
End;
Baud = (B110,B150,B300,B600,B1200,B2400,B4800,B9600);
Parity = (None,Odd,Nevermind,Even);
{Define addresses for COM1 & COM2}
Const RS232:Array [1..2] of INS8250 =
((THR:$3F8;RBR:$3F8;IER:$3F9;
LCR:$3FB;MCR:$3FC;LSR:$3FD;MSR:$3FE),
(THR:$2F8;RBR:$2F8;IER:$2F9;
LCR:$2FB;MCR:$2FC;LSR:$2FD;MSR:$2FE));
Var COM:Byte; {COM1 = 1 and COM2 = 2}
RS_Error:Byte; {Error from serial port}
Buffer:Array [0..4095] of Byte; {4K data comm. buffer}
Buf_Head,Buf_Tail:Integer; {Head/tail buffer pointers}
Regs:Registers; {Passes parms to MSDOS}
Char_In:Integer; {Char read from serial port}
Const Data_Segment:Integer = 0; {Holds contents of DS reg.}
Function Keyin:Integer;
Var Key:Byte;
{This function reads in one keystroke from the keyboard.
If a normal key was pressed, the value is returned in the
low order byte of the integer value. If an "extended" key
(such as a function key) was pressed, the low order byte
contains a zero and the high order byte contains the
extended code}
Begin
Regs.AX:=$0700;
MSDos(Regs);
Key:=Lo(Regs.AX);
If Key = 0 then
Keyin:=Keyin*256
else
Keyin:=Key;
End; {of Keyin}
Procedure RS232_Interrupt;
{This procedure handles interrupts from the serial port.
RS_Error is set to reflect any error result from the port,
but nothing is done with this. The character is read in
from the port and stored in the buffer and Buf_Tail is
incremented. No test is made for buffer overflow.
After all registers have been pushed, the data segment
containing global data is loaded into DX from the
typed constant Data_Segment.}
Begin
Inline ($50/ {PUSH AX}
$53/ {PUSH BX}
$51/ {PUSH CX}
$52/ {PUSH DX}
$57/ {PUSH DI}
$56/ {PUSH SI}
$06/ {PUSH ES}
$1E/ {PUSH DS}
$FB/ {STI}
$2E/$A1/Data_Segment/ {MOV AX,[CS:Data_Segment]}
$8E/$D8); {MOV DS,AX}
RS_Error:=Port[RS232[COM].LSR] and $1E;
Buffer[Buf_Tail]:=Port[RS232[COM].RBR];
Buf_Tail:=(Buf_Tail+1) mod 4096;
Inline ($FA); {CLI}
Port[$20]:=$20; {Clear Interrupt flag}
Inline ($1F/ {POP DS}
$07/ {POP ES}
$5E/ {POP SI}
$5F/ {POP DI}
$5A/ {POP DX}
$59/ {POP CX}
$5B/ {POP BX}
$58/ {POP AX}
$8B/$E5/ {MOV SP,BP}
$5D/ {POP BP}
$CF); {Return} {IRET}
End; {of RS232_Interrupt}
Procedure RS232_Init(Speed:Baud;P:Parity;Stop,Length:Byte);
{This procedure uses Interrupt 14
to initialize the serial port.}
Begin
Regs.DX:=Com-1;
Regs.AX:=Ord(Speed)*32 + Ord(P)*8 + (Stop-1)*4 + Length-5;
Intr($14,Regs);
End; {of RS232_Init}
Function RS232_Out(Param:Byte):Boolean;
Var Counter:Real;
{This function outputs a byte to the serial port.
In the event of a timeout, a value of TRUE is returned.
A timeout occurs if we cannot get Data Set Ready,
Clear to Send, and an empty transmit holding register
after 65535 attempts.}
Begin
Counter:=0;
Port[RS232[COM].MCR]:=$0B;
While
((Port[RS232[COM].MSR] and $30) <> $30) {DSR and CTS}
and
((Port[RS232[COM].LSR] and $20) <> $20) {Tr. Reg empty}
and
(Counter < 65535.0) do {Timeout}
Counter:=Counter+1;
If Counter = 65535.0 then
RS232_Out:=True {We timed out}
Else
Begin
Port[RS232[COM].THR]:=Param;
RS232_Out:=False;
End;
End;
Procedure Initialize;
{This procedure does the following:
1) Changes the appropriate interrupt vector to point to
RS232_Interrupt.
2) Enables the appropriate interrupt on the PC interrupt
controller.
3) Enables the "data ready" interrupt on serial board.}
Begin
Regs.AX:=$250D-Com;
Regs.DS:=CSEG;
Regs.DX:=Ofs(RS232_Interrupt);
MSDos(Regs); {Set up interrupt vector}
If COM = 1 then
Port[$21]:=Port[$21] and $EF {Enable IRQ4}
else
Port[$21]:=Port[$21] and $F7; {Enable IRQ3}
Port[RS232[COM].LCR]:=Port[RS232[COM].LCR] and $7F;
Port[RS232[COM].IER]:=1;
Port[RS232[COM].MCR]:=$08;
End; {of Initialize}
Procedure Cleanup;
{This procedure disables the "data ready" interrupt.}
Begin
Port[$21]:=Port[$21] or $18;
Port[RS232[COM].LCR]:=Port[RS232[COM].LCR] and $7F;
Port[RS232[COM].IER]:=0;
Port[RS232[COM].MCR]:=0;
End; {of Cleanup}
Procedure TTY;
{This procedure provides basic terminal emulation.
Characters read from the keyboard are sent to the serial
port. Characters read from the serial port are sent to
the screen. The procedure is terminated by typing a
CTRL-Z.}
Begin
ClrScr;
Repeat {This code does NOT suppress NULs!}
While Buf_Tail <> Buf_Head Do
Begin {There is data in the buffer}
Write(TRM,Char(Buffer[Buf_Head]));
Buf_Head:=(Buf_Head+1) mod 4096;
End;
If Keypressed then
Begin {Process a keystroke}
Char_In:=Keyin;
If Char_In <> 26 then {Ctrl Z to end}
Begin
If Char_in = 13 then
Write(TRM,Char(10));
If RS232_Out(Lo(Char_In)) then
Writeln(TRM, '*** RS232 Timeout ***');
End;
End;
Until Char_In = 26; {Ctrl Z}
End; {of TTY}
Begin {Outer Block}
COM:=1; {Default to COM1}
Buf_Head:=0;
Buf_Tail:=0;
Data_Segment:=DSEG; {Store the contents of the DS register}
{Init port to 1200 Baud, Even parity, 1 Stop bit, 7 Data bits}
RS232_Init(B1200,Even,1,7);
Initialize;
TTY;
Cleanup;
End.